package app

import (
	"context"
	"fmt"
	"gitee.com/zhucheer/orange/cfg"
	"gitee.com/zhucheer/orange/database"
	"gitee.com/zhucheer/orange/internal"
	"gitee.com/zhucheer/orange/logger"
	orangerequest "gitee.com/zhucheer/orange/request"
	"net/http"
	"strings"
	"time"
)

// ClientSrv http应用注册接口
type ClientSrv interface {
	Register()
}

// 启动应用
func AppStart(client ClientSrv) {
	internal.ConsoleWelCome()

	// 基础服务启动
	baseSrvInit()

	//业务服务注册
	client.Register()

	// 如果有http服务方法则优先执行http服务方法不启动控制台job
	if httpSrv, ok := client.(HttpSrv); ok {
		// 启动http服务
		startHttpSrv(httpSrv)
		return
	}

	if jobSrv, ok := client.(JobSrv); ok {
		// 启动job服务
		startJobSrv(jobSrv)
		return
	}
}

// ConsoleStart 独立启动控制台应用
func ConsoleStart(srv JobSrv) {
	baseSrvInit()
	srv.Register()

	// 启动job服务
	startJobSrv(srv)
	return
}

// baseSrvInit 框架基础服务启动
func baseSrvInit() {
	// 加载配置文件
	cfg.ParseParams()
	cfg.StartEnvFile()
	cfg.StartConfig()
	// 配置加载后检查nacos服务是否需要开启
	NewNacosSrv()

	// 启动logger
	logger.NewLogger()

	// 注册 数据库
	database.RegisterAll()
}

// routerPatten 路由接管
func routerPatten(w http.ResponseWriter, r *http.Request) {
	requestPath := strings.TrimRight(getPath(r), "/")
	if requestPath == "" {
		requestPath = "/"
	}
	method := r.Method

	ctx := NewCtx(context.Background(), w, r)
	ctx.session = sessioinStart(w, r)
	ctx.responseBody.Reset()
	var err error
	ctx.OrangeInput, err = orangerequest.NewInput(r, maxBodySize)
	if err != nil {
		w.WriteHeader(http.StatusRequestEntityTooLarge)
		n, _ := w.Write([]byte("Payload Too Large"))
		w.Header().Add("Content-Length", fmt.Sprintf("%d", n))
		return
	}

	runTime := time.Now()
	defer httpAfterDo(ctx, runTime)

	httpHandler, httpMiddleware := routers.Find(method, requestPath, ctx)
	routerHandlerFunc(httpHandler, httpMiddleware, ctx)

	return
}

// 处理HTTP controller
func routerHandlerFunc(httpHandler HandlerFunc, middlewares []MiddleWare, ctx *Context) {
	routeFuncDo := func() HandlerFunc {
		if httpHandler != nil {
			return httpHandler
		}
		return NotFoundHandler
	}

	// 中间件依次调用
	var middleHandlerFunc = routeFuncDo()
	if middlewares != nil && len(middlewares) > 0 {
		for _, item := range middlewares {
			middleFunc := item.Func()
			middleHandlerFunc = middleFunc(middleHandlerFunc)
		}
	}

	if ctx.srvType == srvTypeHttp && cfg.GetBool("app.csrfVerify", cfg.ConfigDef.GetBool("app.csrfVerify")) == true {
		ctx.CsrfToken = startCsrfToken(ctx.Session())
		middleHandlerFunc = checkCsrfToken(middleHandlerFunc)
	}
	middleHandlerFunc = accessLog(middleHandlerFunc)

	middleHandlerFunc(ctx)
}

// httpAfterDo http后置操作
func httpAfterDo(c *Context, runTime time.Time) error {
	// http类型服务处理通用session/跳转操作, grpc类型不处理通用session
	if c.srvType == srvTypeHttp {
		if err := c.session.SessionRelease(c.response); err != nil {
			logger.Error("session release error:%v", err)
		}

		if c.redirect != "" {
			http.Redirect(c.response, c.request, c.redirect, http.StatusFound)
			return nil
		}
	}

	if c.responseStatus > 0 {
		c.response.WriteHeader(c.responseStatus)
	}
	// 最后输出body
	c.response.Write(c.responseBody.Bytes())

	// 异步执行后置操作
	for _, itemFunc := range c.afterDelayDoFuncs {
		go func(item afterDelayFunc) {
			time.Sleep(item.delay)
			item.doFunc(c)
		}(itemFunc)
	}
	c.ms = time.Since(runTime)

	//c.responseBody.Reset()
	return nil
}
